use anyhow::anyhow;
use anyhow::Result;
use chrono::Local;
use eastmoney;
use fudata::db;
use fudata::model::security;
use fudata::model::FudaRecord;
use log::debug;
use log::error;
use log::info;
use reqwest::Client;

use crate::helper;

/// 开放基金排行
///
/// date: e.g. 2023-03-18
///
/// @param   pn: page index, start from 1,
///
/// @param   pz: page size
///
pub async fn update_opf_list_page_from_eastmoney(
    date: &str,
    pn: u16,
    pz: u16
) -> Result<Vec<FudaRecord>> {
    info!("update_opf_list_page_from_eastmoney 1 ");
    let opf_list: eastmoney::fund::funds_ranking::FundRanking = eastmoney::fund::funds_ranking::FundRanking
        ::fund_rankhandler(date, pn, pz).await
        .map_err(|err| anyhow!(err.to_string()))?;

    info!("update_opf_list_page_from_eastmoney 2 opf_list.datas.len={:?}", opf_list.datas.len());

    let mut updates = Vec::new();
    for (idx, fd) in opf_list.datas().iter().enumerate() {
        let code = fd.code.clone();
        let name = fd.name.clone();
        let market = helper::get_stock_market(&fd.code); //.map_err(|err| anyhow!(err.to_string()));
        match market {
            Ok(mkt) => {
                debug!(
                    "opf_list.datas[{}]{mkt}.{}.{}, {}",
                    (pn - 1) * pz + (idx as u16),
                    security::SecurityType::OPF,
                    &code,
                    &name
                );

                let security = security::Security {
                    market: mkt,
                    type_: security::SecurityType::OPF,
                    symbol: code,
                    name: Some(name),
                    ..Default::default()
                };

                // Update a security record
                let updated: Option<FudaRecord> = db::security::upsert(&security).await?;

                if let Some(u) = updated {
                    updates.push(u);
                }
            }
            Err(e) => error!("\n*** update_opf_list_page_from_eastmoney, {}", e),
        }
    }
    info!("update_opf_list_page_from_eastmoney 3 updates.len={}", updates.len());
    Ok(updates)
}

pub async fn update_opf_list_all_from_eastmoney() -> Result<()> {
    let mut pn = 1;
    let pz = 1000;
    let prev_tradeday = helper::previous_trading_day(&Local::now());
    let yesterday = &prev_tradeday.format("%Y-%m-%d").to_string();
    // let yesterday = "2024-06-28";
    loop {
        info!(
            "(opfs_craw::update_opf_list_all_from_eastmoney) start! for page: {pn} page-size: {pz}"
        );
        let rs = update_opf_list_page_from_eastmoney(yesterday, pn, pz).await;
        match rs {
            Ok(records) => {
                if records.is_empty() {
                    info!("debug No more records available; exit the loop");

                    break; // No more records available; exit the loop
                }
                pn += 1; // Increment the page number for the next request
                debug!("..{}", pn);
            }
            Err(error) => {
                // 错误处理: 打印错误日志并采取相应措施
                error!("Update error on page {}: {:?}", pn, error);

                return Err(error); // An error occurred; exit the loop
            }
        }
        info!(
            "(opfs_craw::update_opf_list_all_from_eastmoney) /end! for page: {pn} page-size: {pz}"
        );
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use crate::fund::opfs_craw;
    use crate::helper;

    use chrono::Duration;
    use chrono::Local;

    use log::debug;
    use serde::Deserialize;

    #[derive(Debug, Deserialize, PartialEq)]
    struct Count {
        count: u64,
    }

    #[tokio::test]
    async fn test_update_opf_list_page_from_eastmoney() {
        pretty_env_logger::init_timed();
        let _ = fudata::db::init().await.unwrap();

        // Format today's date as a string in the format "YYYY-MM-DD"
        let prev_tradeday = helper::previous_trading_day(&Local::now());
        let yesterday = &prev_tradeday.format("%Y-%m-%d").to_string();
        // let yesterday = "2024-06-28";

        let mut pn = 1;
        let pz = 1000;
        while pn < 102 {
            let rs = opfs_craw::update_opf_list_page_from_eastmoney(yesterday, pn, pz).await;
            match rs {
                Ok(records) => {
                    if records.is_empty() {
                        break; // No more records available; exit the loop
                    }
                    pn += 1; // Increment the page number for the next request
                    debug!("..{}", pn);
                }
                Err(error) => {
                    // 错误处理: 打印错误日志并采取相应措施
                    debug!("Update error on page {}: {:?}", pn, error);
                    break; // An error occurred; exit the loop
                }
            }
        }
    }
}
